package com.haiqiu.busines.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import lombok.extern.slf4j.Slf4j;
import com.haiqiu.common.entity.WebSockMsg;
import com.haiqiu.common.exception.BaseException;
import com.haiqiu.common.utils.web.RedisUtil;
import com.haiqiu.common.utils.web.SpringUtil;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author HaiQiu
 * @date 2021/10/15
 * @desc webSocket服务处理
 */
@Slf4j
@Component
@ServerEndpoint("/ws/{username}")
public class WebSocketServer {

    //实例化redis对象，通过自定义的SpringContextHolder在bean容器中获取chatRedisUtil对象
    RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

    /**
     * 当前连接人数
     */
    private static int onlineCount = 0;
    /**
     * 存储当前用户列表
     */
    private static Map<String, WebSocketServer> cilents = new ConcurrentHashMap<>();
    /**
     * 用户session
     */
    private Session session;
    /**
     * 用户名
     */
    private String username;


    /**
     * 打开链接
     *
     * @param username 用户名
     * @param session  session
     */
    @OnOpen
    public void onOpen(@PathParam("username") String username, Session session) {
        this.username = username;
        this.session = session;
        WebSocketServer.onlineCount++;
        cilents.put(username, this);
        log.info(String.format("%s已接入WebSocket服务器，当前在线人数%d", username, onlineCount));
    }

    @OnClose
    public void onClose() {
        cilents.remove(username);
        WebSocketServer.onlineCount--;
        log.error(username + "已退出WebSocket服务器连接");
//        userService.removeOnlineUser(username);
    }

    /**
     * 接受客户端发送到服务器的消息
     *
     * @param message 消息信息
     */
    @OnMessage
    public void onMessage(String message) {
        log.info("客户端：" + message + ",已收到");
        WebSockMsg webSockMsg = inspectParams(message);
        //获取指定发送的人
        if (!StringUtils.isEmpty(webSockMsg.getTo()) && webSockMsg.getChatType() == 2) {
            sendMessage(webSockMsg.getTo(), webSockMsg.getContent());
            //如果是同步在线状态
        } else if (webSockMsg.getMsgType() == 6) {
            log.info(String.format("%s用户已经在线了", username));
        } else {
            sendMessage(webSockMsg.getContent());
        }
    }


    @OnError
    public void onError(Session session, Throwable throwable) {
        throwable.printStackTrace();
        log.error("WebSocket发生错误：" + throwable.getMessage());
    }

    /**
     * 发送到指定接收人
     *
     * @param username 指定人
     * @param message  消息内容
     */
    public static void sendMessage(String username, String message) {
        //发送到指定接收人
        WebSocketServer socketServer = WebSocketServer.cilents.get(username);
        socketServer.session.getAsyncRemote().sendText(message);
        log.info("【WebSocket】发送消息给" + socketServer + ",message={}", message);
    }

    /**
     * 后台发送数据到所有人
     *
     * @param message 消息体
     */
    public static void sendMessage(String message) {
        // 向所有连接websocket的客户端发送消息
        // 可以修改为对某个客户端发消息
        for (WebSocketServer item : cilents.values()) {
            item.session.getAsyncRemote().sendText(message);
        }
        log.info("【WebSocket】广播消息,message={}", message);
    }

    /**
     * 后台发送数据到所有人
     *
     * @param message 消息体
     */
    public void sendMsgAll(String message) {
        // 向所有连接websocket的客户端发送消息
        // 可以修改为对某个客户端发消息
        for (WebSocketServer item : cilents.values()) {
//            log.info("在线客户端："+item.username);
            item.session.getAsyncRemote().sendText(message);
        }
//        log.info("【WebSocket】广播消息,message={}", message);
    }


    /**
     * 处理参数检验
     *
     * @param message 消息体
     * @return 封装消息体
     */
    private static WebSockMsg inspectParams(String message) {
        if (StringUtils.isEmpty(message)) {
            throw new BaseException("消息体为空");
        }
        WebSockMsg webSockMsg = null;
        try {
            webSockMsg = JSON.parseObject(message, WebSockMsg.class);
        } catch (JSONException e) {
            throw new JSONException("消息体格式不正确", new Throwable("消息体格式不正确"));
        }
        if (webSockMsg == null) {
            throw new RuntimeException(new Throwable("消息体格式不正确"));
        }
        if (!(webSockMsg.getChatType() == 0 || webSockMsg.getChatType() == 1 || webSockMsg.getChatType() == 2)) {
            throw new RuntimeException(new Throwable("聊天类型错误"));
        }
        if (!(webSockMsg.getMsgType() == 0 || webSockMsg.getMsgType() == 1
                || webSockMsg.getMsgType() == 2 || webSockMsg.getMsgType() == 3
                || webSockMsg.getMsgType() == 4 || webSockMsg.getMsgType() == 5 || webSockMsg.getMsgType() == 6)) {
            throw new RuntimeException(new Throwable("消息类型错误"));
        }
        if (StringUtils.isEmpty(webSockMsg.getFrom())) {
            throw new RuntimeException(new Throwable("发送者用户名为空"));
        }
//        if (StringUtils.isEmpty(webSockMsg.getTo())) {
//            throw new RuntimeException(new Throwable("接收者者用户名为空"));
//        }
        return webSockMsg;
    }
}
